package com.huaxin.dss2.data.bean.properties;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Maps;
import java.util.HashMap;
import java.util.Map;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

/**
 * @author : luqing
 * @date : 2018/12/27 14:28
 */
@Component
public class PropertiesTrie {

    private class Node{

        /**
         * 该字串的重复数目，即节点数,取值为0、1、2、3、4、5……
         */
        private int deepNum;
        /**
         * 以该字串为前缀的字串数
         */
        private int prefixNum;

        /**
         * 子节点
         */
        private Map<String,Node> childMap;

        /**
         * 值
         */
        private Object value;

        /**
         * 是否为单词节点
         */
        private boolean isLeaf;
        private Node(){
            deepNum =0;
            prefixNum =0;
            isLeaf=false;
            childMap = Maps.newHashMap();
        }

        public Object getValue() {
            return value;
        }

        public void setValue(Object value) {
            this.value = value;
        }

        public boolean isLeaf() {
            return isLeaf;
        }

        public void setLeaf(boolean leaf) {
            isLeaf = leaf;
        }
    }


    /**
     * 树根节点
     */
    private Node root;

    public PropertiesTrie(){
        ///初始化trie 树
        root=new Node();
    }

    public Node getRoot() {
        return this.root;
    }

    /**
     * 插入key-value，用循环代替迭代实现
     * @param key propertiesKey
     */
    public void insert(String key,Object value){
        insert(getRoot(), key,value);
    }
    /**
     * 插入字串，用循环代替迭代实现
     * @param root 根节点
     * @param key propertiesKey
     * @param value propertiesValue
     */
    private void insert(Node root,String key,Object value){
        key=key.toLowerCase();
        String[] sp = key.split("\\.");

        for(int i=0,length=sp.length; i<length; i++){
            ///用相对于a字母的值作为下标索引，也隐式地记录了该字母的值
            Node node = root.childMap.get(sp[i]);

            if (node != null){
                node.prefixNum++;
            }else {
                node = new Node();
                node.setValue(value);
                root.childMap.put(sp[i],node);
                node.prefixNum++;
            }

            ///如果到了字串结尾，则做标记
            if(i==length-1){
                node.isLeaf = true;
                root.deepNum++;
            }
            ///root指向子节点，继续处理
            root = node;
        }
    }




    /**
     * 遍历Trie树，查找所有的words以及出现次数
     * @return HashMap<String,Integer> map
     */
    public HashMap<String,Object> getAllKeys(){
//		HashMap<String, Integer> map=new HashMap<String, Integer>();

        return preTraversal(getRoot(), "");
    }

    /**
     * 前序遍历。
     * @param root		子树根节点
     * @param prefixs	查询到该节点前所遍历过的前缀
     * @return 所有节点
     */
    private HashMap<String,Object> preTraversal(Node root,String prefixs){
        HashMap<String, Object> map=new HashMap<>();

        if(root!=null){
            if(root.isLeaf){
                ////当前即为一个单词
                map.put(prefixs, root.getValue());
            }

            for (Map.Entry<String,Node> entry : root.childMap.entrySet()){
                if (!StringUtils.isEmpty(prefixs.trim())){
                    prefixs += ".";
                }
                String tempstr = prefixs + entry.getKey();
                map.putAll(preTraversal(entry.getValue(),tempstr));
            }
        }

        return map;
    }


    /**
     * 判断某key是否在树中
     * @param key
     * @return true if exists ,otherwise  false
     */
    public boolean isExist(String key){
        return search(getRoot(), key);
    }
    /**
     * 查询某key是否在树中
     * @param key propertiesKey
     * @return true if exists ,otherwise  false
     */
    private boolean search(Node root,String key){
        return getNode(root,key)!=null;
    }

    /**
     * 得到以某字串为前缀的字串集，包括字串本身！ 类似单词输入法的联想功能
     * @param prefix 字串前缀
     * @return 字串集以及出现次数，如果不存在则返回null
     */
    public HashMap<String, Object> getKeysForPrefix(String prefix){
        return getWordsForPrefix(getRoot(), prefix);
    }
    /**
     * 得到以某key为前缀的字串集，包括key本身！
     * @param root 根节点
     * @param prefix 前缀
     * @return 字串集以及出现次数
     */
    private HashMap<String, Object> getWordsForPrefix(Node root,String prefix){
        Node node = getNode(root,prefix);
        return preTraversal(node==null?root:node, prefix);
    }

    private Node getNode(Node root,String prefix){

        if (StringUtils.isEmpty(prefix)){
            return root;
        }

        String preSp[] = prefix.toLowerCase().split("\\.");
        Node node = null;
        ///结果包括该前缀本身
        ///此处利用之前的前序搜索方法进行搜索
        for (String aPreSp : preSp) {
            node = root.childMap.get(aPreSp);
            if (node == null || node.childMap.isEmpty()) {
                return null;
            }
            root = node;
        }

        return node;
    }

    public JSONObject childToJson(String pre){
        Node node = getNode(root,pre);
        return (JSONObject) toChildJson(node,pre);
    }

    private Object toChildJson(Node root,String pre){
        JSONObject result = new JSONObject();
        if(root!=null){
            if(root.isLeaf){
                ////当前即为一个单词
                return root.getValue();
            }

            StringBuilder preBuilder = new StringBuilder(pre);
            for (Map.Entry<String,Node> entry : root.childMap.entrySet()){
                if (!StringUtils.isEmpty(preBuilder.toString().trim())){
                    preBuilder.append(".");
                }
                String tempStr = preBuilder + entry.getKey();
                result.put(entry.getKey(),toChildJson(entry.getValue(),tempStr));
            }
        }

        return result;
    }

    public <T> void copyProperties(String pre,T obj){
        Object t = JSON.toJavaObject(childToJson(pre), obj.getClass());
        BeanUtils.copyProperties(t,obj);
    }

}

